#pragma once
#include <memory>
#include <string>
#include <glm/glm.hpp>
#include <DataCore/buffer_data.h>
#include <Geometry/smesh.h>
#include <Dynamics/Material/FemMaterial/fem_material.h>
#include <Dynamics/Material/PdmMaterial/pdm_material.h>
#include <Dynamics/Pdm/pdm_weight_type.h>

namespace PhysLeo{

/**
 * shared simulation data belongs to a real object.
 * contains a lot of buffer data and some property data. all the buffer data is managed by std::shared_ptr.
 */
template<typename T>
class SimData{
public:
    /**
     * empty constructor
     */
    SimData();

    /**
     * delete the default copy constructor
     */
    SimData(const SimData<T>&) = delete;

    /**
    * delete the default move constructor
    */
    SimData(SimData<T>&&) = delete;

    /**
    * delete the default copy assignment function
    */
    SimData<T>& operator=(const SimData<T>&) = delete;

    /**
    * delete the default move assignment function
    */
    SimData<T>& operator=(SimData<T>&&) = delete;

    //default destructor
    ~SimData() = default;

    /**
     * read geometry data from geometry file like smesh
     * @param smesh  Smesh type, geometry input 
     */
    void readGeometry(Smesh &smesh);

    /**
     * read ini config file to get more simulation data
     * @param filename   file path to the simulation config file xxx.ini
     */
    void readSimulationConfig(const std::string &filename);

protected:
    /**
     * read element material file to get the volume, mass, material parameters like young's module and poisson ratio distribution of object
     * @param filename  file path to the element material(Fem material) file 
     */
    void readElementMaterial(const std::string &filename);

    /**
    * read vertex material file to get the volume, mass, material parameters like young's module and poisson ratio distribution of object
    * @param filename  file path to the vertices material(Pdm material) file
    */
    void readVertexMaterial(const std::string &filename);

    /**
     * read fixed freedom file to set fixed_freedom_ vector
     * @param filename  file path to the fixed freedom file
     */
    void readFixedFreedom(const std::string &filename);

    //__________________________________________Buffer Data_____________________________________________________
public:
    /**
     * rest position
     */
    std::shared_ptr<BufferData<glm::tvec3<T>>> ptr_rest_pos_;

    /**
    * current position
    */
    std::shared_ptr<BufferData<glm::tvec3<T>>> ptr_pos_;

    /**
    * element vertices index
    */
    std::shared_ptr<BufferData<int>> ptr_ele_;

    /**
    * velocity
    */
    std::shared_ptr<BufferData<glm::tvec3<T>>> ptr_vel_;

    /**
    * force
    */
    std::shared_ptr<BufferData<glm::tvec3<T>>> ptr_force_;

    /**
    * fixed freedom.
    * if you want to fix x,y,z coordinates of point index 0, you need to put 0,1,2 into this buffer
    */
    std::shared_ptr<BufferData<int>> ptr_fix_;

    /**
    * volume of vertex
    */
    std::shared_ptr<BufferData<T>> ptr_vert_volume_;

    /**
    * volume of element
    */
    std::shared_ptr<BufferData<T>> ptr_ele_volume_;

    /**
    * mass of vertex
    */
    std::shared_ptr<BufferData<T>> ptr_mass_;

    /**
    * material of element
    */
    std::shared_ptr<BufferData<T>> ptr_ele_material_;

    /**
    * material of vertex
    */
    std::shared_ptr<BufferData<T>> ptr_vert_material_;

    //________________________________________________________Property Data____________________________________________________________

    /**
    * whether material in the object is homogeneous
    */
    bool homogeneous_;

    /**
     * velocity damping parameter
     */
    T velocity_damping_param_;

    /**
     * gravity acceleration
     */
    glm::tvec3<T> gravity_acceleration_;

    //--------------------------------FEM---------------------------------------

    /**
    * element type
    */
    EleType ele_type_;

    /**
    * fem material type
    */
    FemMaterialType fem_material_type_;

    /**
    * gauss quadrature points for fem method
    */
    int quadrature_points_;

    //--------------------------------PDM---------------------------------------

    /**
    * PDM horizon radius
    */
    T horizon_radius_;

    /**
    * pdm material type
    */
    PdmMaterialType pdm_material_type_;

    /**
    * whether add the invertible energy 
    */
    bool pdm_invertible_;

    /**
    * PDM weight type
    */
    PdmWeightType pdm_weight_type_;
};

}
